﻿using MEF_Test.Bricks.StronglyTypedExports;

namespace Subtitles.OpenSubtitlesIsdbSubtitlesProvider
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.Composition;
    using System.IO;
    using System.Linq;

    using MEF_Test.Bricks.Subtitles;
    using MEF_Test.Contracts;
    using MEF_Test.Subtitles;

    using Mydra.IsdbTools;

    [Export(typeof(ISubtitlesProvider))]
    public class OpenSubtitlesIsdbSubtitlesProvider : SubtitlesProviderBase//, IOpenSubtitlesIsdbSubtitlesProvider
    {
        [ImportingConstructor]
        public OpenSubtitlesIsdbSubtitlesProvider(ISubtitleFormatHandlersProvider subtitleFormatHandlersProvider)
            : base(subtitleFormatHandlersProvider)
        {
            
        }
        #region Constants and Fields

        /// <summary>
        /// The label caption of the current provider.
        /// </summary>
        private const string PROVIDER_NAME = "Open Subtitles (ISDb Mode)";

        /// <summary>
        /// holds the last ticket to have been received within a subtitle-query response
        /// </summary>
        private string _latestTicket;

        #endregion

        #region Public Methods

        /// <summary>
        /// Downloads the subtitle file.
        /// </summary>
        /// <param name="subtitleID">The subtitle ID.</param>
        /// <returns>
        /// A stream to the content of the subtitle file.
        /// </returns>
        public override Stream OpenSubtitleFile(int subtitleID)
        {
            return IsdbProtocol.DownloadIsdbSubtitle(subtitleID, _latestTicket);
        }

        /// <summary>
        /// Gets the name of the provider.
        /// </summary>
        /// <returns>The name of the subtitles provider.</returns>
        public override string GetProviderName()
        {
            return PROVIDER_NAME;
        }

        /// <summary>
        /// Gets the subtitles.
        /// </summary>
        /// <param name="node">The media node.</param>
        /// <returns>
        /// The subtitles descriptions grouped by provider
        /// </returns>
        public override IEnumerable<ISubtitleViewModel> GetSubtitles(IBrowserNodeViewModel node)
        {
            string fileName = "irrelevant";
            string userAgent = "Mydra Center";
            var movieHash = IsdbHashesHelper.ToHexadecimal(IsdbHashesHelper.ComputeMovieHash(node.FileHandler.GetStream()));

            IsdbProtocol.UserAgent = userAgent;
            
            IEnumerable<IIsdbMovie> movies = IsdbProtocol.GetSubtitlesPerMovie(fileName, node.FileHandler.GetStream().Length, movieHash, out _latestTicket);

            // copy IsdbMovie infos to SubtitlesViewModel
            var subtitleViewModels = from movie in movies
                                     from subtitle in movie.Subtitles
                                     select new OpenSubtitlesIsdbViewModel(subtitle, this, this.SubtitleFormatHandlersProvider.SafeGetSubtitleFormatHandler(subtitle.Format));

            return subtitleViewModels;
        }

        #endregion
    }

    public class OpenSubtitlesIsdbViewModel : SubtitleViewModelBase
    {
        /// <summary>
        /// The subtitles provider to rely on and use in <see cref="GetSubtitleFile"/>.
        /// </summary>
        private readonly ISubtitlesProvider _provider;

        /// <summary>
        /// Initializes a new instance of the <see cref="OpenSubtitlesIsdbViewModel"/> class.
        /// </summary>
        /// <param name="isdbSubtitle">The isdb subtitle.</param>
        /// <param name="openSubtitlesIsdbSubtitlesProvider">The open subtitles isdb subtitles provider.</param>
        /// <param name="subtitleFormatHandler"></param>
        public OpenSubtitlesIsdbViewModel(IIsdbSubtitle isdbSubtitle, ISubtitlesProvider openSubtitlesIsdbSubtitlesProvider, ISubtitleFormatHandler subtitleFormatHandler)
        {
            if (openSubtitlesIsdbSubtitlesProvider == null)
            {
                throw new ArgumentNullException("openSubtitlesIsdbSubtitlesProvider");
            }

            if (subtitleFormatHandler == null) throw new ArgumentNullException("subtitleFormatHandler");

            _provider = openSubtitlesIsdbSubtitlesProvider;

            ID = isdbSubtitle.ID;
            Name = isdbSubtitle.Name;
            SubtitleFormatHandler = subtitleFormatHandler;
        }      

        /// <summary>
        /// Gets or sets the ID.
        /// </summary>
        /// <value>The subtitle ID.</value>
        public int ID { get; set; }

        /// <summary>
        /// Gets or sets the name.
        /// </summary>
        /// <value>The subtitle filename.</value>
        public string Name { get; set; }

        /// <summary>
        /// Gets the content of the actual subtitles file.
        /// </summary>
        /// <returns>the text-based content of the subtitles file.</returns>
        public override Stream GetSubtitleFile()
        {
            return _provider.OpenSubtitleFile(ID);
        }
    }


    [Export(typeof(ISubtitleFormatHandlersProvider))]
    public class SubtitleFormatHandlersProvider : ISubtitleFormatHandlersProvider
    {
        private readonly IEnumerable<Lazy<ISubtitleFormatHandler, ISubtitleFormatHandlerExportAttribute>> _subtitleFormatHandlers;

        [ImportingConstructor]
        public SubtitleFormatHandlersProvider([ImportMany(typeof(ISubtitleFormatHandler))] IEnumerable<Lazy<ISubtitleFormatHandler, ISubtitleFormatHandlerExportAttribute>> subtitleFormatHandlers)
        {
            this._subtitleFormatHandlers = subtitleFormatHandlers;
        }

        public ISubtitleFormatHandler GetSubtitleFormatHandler(string format)
        {
            var handler = TryGetSubtitleFormatHandler(format);
            if (handler == null)
            {
                throw new FormatException(String.Format("No subtitles format handler could be found for the followinf subtitles format : {0}", format));                
            }
            return handler;
        }

        public ISubtitleFormatHandler TryGetSubtitleFormatHandler(string format)
        {
            var subtitleFormatHandler = from handler in _subtitleFormatHandlers
                                        where handler.Metadata.FileExtension.Equals(format, StringComparison.OrdinalIgnoreCase)
                                        select handler;
            var lazyHandler = subtitleFormatHandler.SingleOrDefault();
            if (lazyHandler != null)
            {
                return lazyHandler.Value;
            }
            return null;
        }

        public ISubtitleFormatHandler SafeGetSubtitleFormatHandler(string format)
        {
            var handler = TryGetSubtitleFormatHandler(format);
            if (handler == null)
            {
                handler = new DummySubtitleFormatHandler();
            }
            return handler;
        }
    }

    /// <summary>
    /// A dummy subtitle format handler to use with the <see cref="SubtitleFormatHandlersProvider.SafeGetSubtitleFormatHandler"/> method in case no valid format handler was found.
    /// </summary>
    public class DummySubtitleFormatHandler : ISubtitleFormatHandler
    {
        public ISubtitleHandler Create(Stream subtitle)
        {
            throw new NotImplementedException();
        }
    }
}
